<template>
  <div class="split" style="height: 66vh; --left-pane-w: 260px">
    <div class="left">
      <div class="tree-viewport">
        <el-tree
          :key="treeKey"
          ref="treeRef"
          :data="nodes"
          node-key="id"
          :props="treeProps"
          :default-expanded-keys="expandedKeys"
          highlight-current
          :expand-on-click-node="false"
          :filter-node-method="filterNode"
          class="tree leveled asset-tree edit-form"
          style="height: 66vh"
          @node-expand="onCaretExpand"
          @node-collapse="onCaretCollapse"
        >
          <template #default="{ node, data }">
            <div
              class="node-line"
              :style="{ '--lvl-color': levelColor(data.level) }"
              @click.stop="handleNodeClick(node)"
              @dblclick.stop="handleNodeDblClick(node)"
            >
              <div class="node-left">
                <!-- <el-icon v-if="typeText(data) === '系统'"><Cpu /></el-icon>
                <el-icon v-else-if="typeText(data) === '母设备'"
                  ><Setting
                /></el-icon>
                <el-icon v-else-if="typeText(data) === '子设备'"
                  ><Cpu
                /></el-icon>
                <el-icon v-else-if="typeText(data) === '部件'"
                  ><Tools
                /></el-icon>
                <el-icon v-else><Cpu /></el-icon> -->

                <el-icon>
                  <component :is="iconOf(data)" />
                </el-icon>

                <span class="font-500 name-colored" :title="dispName(data)">
                  {{ dispName(data) }}
                </span>

                <!-- 仅根节点显示：一键“展开所有/收起所有” -->
                <div class="root-tools" v-if="isRootNode(node)">
                  <!-- <span
                    class="root-arrow"
                    :class="{ open: allOpen }"
                    :title="allOpen ? '收起所有' : '展开所有'"
                    @click.stop="toggleExpandAll"
                  >
                    {{ allOpen ? "↑" : "↓" }}
                  </span> -->
                </div>
              </div>

              <div class="node-right">
                <el-tag
                  size="small"
                  class="tag-soft"
                  :style="softTagStyle(typeText(data))"
                >
                  {{ shortType(typeText(data)) }}
                </el-tag>
              </div>
            </div>
          </template>
        </el-tree>
      </div>
    </div>

    <div class="right" v-loading="rightLoading">
      <div class="actions">
        <el-tooltip content="新增子项" placement="top">
          <el-button circle size="small" type="success" plain @click="doAdd()">
            <el-icon><Plus /></el-icon>
          </el-button>
        </el-tooltip>
        <el-tooltip content="修改" placement="top">
          <el-button circle size="small" type="warning" plain @click="doEdit()">
            <el-icon><Edit /></el-icon>
          </el-button>
        </el-tooltip>
        <el-tooltip content="删除" placement="top">
          <el-button
            circle
            size="small"
            type="danger"
            plain
            @click="doRemove()"
          >
            <el-icon><Delete /></el-icon>
          </el-button>
        </el-tooltip>
        <el-tooltip content="设备备件更换历史" placement="top">
          <el-button
            circle
            size="small"
            type="primary"
            plain
            @click="doHistory()"
          >
            <el-icon><Timer /></el-icon>
          </el-button>
        </el-tooltip>
      </div>

      <el-empty
        v-if="!detail"
        description="点击左侧叶子查看详情；行点击/小三角=仅展开到下一层"
      />
      <el-descriptions v-else :column="4" border class="kv-desc">
        <el-descriptions-item label="层级路径" :span="4">
          <div class="path-row">
            <span class="path" :title="pathText">{{ pathText || "-" }}</span>
            <el-tooltip content="复制路径" placement="top">
              <el-button
                circle
                size="small"
                type="primary"
                plain
                @click.stop="copyPath"
              >
                <el-icon><CopyDocument /></el-icon>
              </el-button>
            </el-tooltip>
          </div>
        </el-descriptions-item>

        <!-- <el-descriptions-item label="层级路径" :span="3">
          <span class="path">{{ getPath ? getPath(detail.id) : detail.path || "-" }}</span>
        </el-descriptions-item> -->
        <el-descriptions-item label="设备名称">{{
          fmt(detail.name)
        }}</el-descriptions-item>
        <el-descriptions-item label="设备编码">{{
          fmt(detail.code)
        }}</el-descriptions-item>
        <el-descriptions-item label="设备规格">{{
          fmt(detail.specification)
        }}</el-descriptions-item>
        <el-descriptions-item label="设备类别">{{
          fmt(detail.beType)
        }}</el-descriptions-item>
        <el-descriptions-item label="设备材质">{{
          fmt(detail.material)
        }}</el-descriptions-item>
        <el-descriptions-item label="设备区域">{{
          fmt(detail.area)
        }}</el-descriptions-item>
        <el-descriptions-item label="设备模块">{{
          fmt(detail.mokuai)
        }}</el-descriptions-item>
        <el-descriptions-item label="设备数量">{{
          fmt(detail.quantity) + detail.unit
        }}</el-descriptions-item>

        <!-- 有值才带单位；单位建议标准化：万 / ℃ / MPa / kW -->
        <el-descriptions-item label="设备金额">{{
          fmtUnit(detail.amount, "万")
        }}</el-descriptions-item>
        <el-descriptions-item label="设计温度">{{
          fmtUnit(detail.designTemp, "℃")
        }}</el-descriptions-item>
        <el-descriptions-item label="设计压力">{{
          fmtUnit(detail.designPress, "MPa")
        }}</el-descriptions-item>
        <el-descriptions-item label="电机功率">{{
          fmtUnit(detail.motorPower, "kW")
        }}</el-descriptions-item>

        <el-descriptions-item label="搅拌方式">{{
          fmt(detail.mixingType)
        }}</el-descriptions-item>
        <el-descriptions-item label="设备品牌">{{
          fmt(detail.brand)
        }}</el-descriptions-item>
        <el-descriptions-item label="设备型号">{{
          fmt(detail.model)
        }}</el-descriptions-item>
        <el-descriptions-item label="制造厂家">{{
          fmt(detail.manufacturer)
        }}</el-descriptions-item>

        <!-- 备件清单：逐个显示 名称 / 代码 / 可用 / 总 <el-descriptions-item class="dl-break" :span="3" /> -->
        <el-descriptions-item label="备件信息" :span="4">
          <div
            class="spares-grid"
            :style="{ '--cols': totalCols }"
            v-if="spareList.length"
          >
            <!-- 表头 -->
            <div class="sp-head name">名称</div>
            <div class="sp-head code">编码</div>
            <div class="sp-head">当前库存</div>
            <div class="sp-head">最低库存</div>
            <div class="sp-head">最高库存</div>

            <!-- <div class="sp-head">总库存</div>
    <div class="sp-head">使用数量</div> -->

            <!-- 行数据 -->
            <template v-for="sp in spareList" :key="sp.id || sp.code">
              <div class="sp-cell sp-name" :title="sp?.name">
                {{ sp?.name ?? "-" }}
              </div>
              <div class="sp-cell sp-code">
                <el-tag size="small" class="code-pill" v-if="sp?.code">{{
                  sp.code
                }}</el-tag>
                <span v-else>—</span>
              </div>
              <div class="sp-cell sp-avai">
                <span class="num-badge">{{ sp?.stockAvailable ?? 0 }}</span>
              </div>
              <div class="sp-cell sp-total">
                <span class="num-badge plain">{{ sp?.minStock ?? 0 }}</span>
              </div>
              <div class="sp-cell sp-total">
                <span class="num-badge plain">{{ sp?.maxStock ?? 0 }}</span>
              </div>
              <!-- <div class="sp-cell sp-total"><span class="num-badge plain">{{ sp?.stockTotal ?? 0 }}</span></div>
      <div class="sp-cell sp-total"><span class="num-badge plain">{{ used(sp) }}</span></div> -->
            </template>
          </div>
          <span v-else>-</span>
        </el-descriptions-item>
        <el-descriptions-item label="创建时间" :span="2">{{
          detail.createTime || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="更新时间" :span="2">{{
          detail.updateTime || "-"
        }}</el-descriptions-item>
        <!-- <el-descriptions-item label="更新时间">{{ detail.updateTime || "-" }}</el-descriptions-item>
        <el-descriptions-item label="备注" :span="2">{{ detail.remark || "-" }}</el-descriptions-item> -->
      </el-descriptions>
    </div>
  </div>
</template>

<script setup>
import { ref, watch, nextTick, computed } from "vue";
import {
  Setting,
  Tools,
  Cpu,
  Plus,
  Edit,
  Delete,
  Timer,
  CopyDocument,
} from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
 

const totalCols = ref(5);
/** props */
const props = defineProps({
  nodes: { type: Array, default: () => [] },
  detailMap: { type: [Object, Map], default: () => ({}) },
  getPath: { type: Function, default: null },
  loadDetail: { type: Function, default: null },
  onAdd: { type: Function, default: null },
  onEdit: { type: Function, default: null },
  onRemove: { type: Function, default: null },
  onHistory: { type: Function, default: null },
  onRefresh: { type: Function, default: null },
});

/** refs & state */
const treeRef = ref(null);
const treeProps = { label: "label", children: "children" };
const expandedKeys = ref([]);
const treeKey = ref(0);
const detail = ref(null);
const selectedId = ref(null);
const rightLoading = ref(false);

/** 全局展开状态（仅用于根节点自定义箭头展示“展开所有/收起所有”） */
const allOpen = ref(false);

/** 防“程序性展开”触发 caret 事件 */
const suppressAuto = ref(false);




const TYPE_ICON = {
  SYSTEM: Setting,     // 系统 → 齿轮
  MACHINE: Cpu,        // 母设备 → 设备/芯片
  MODULE: Cpu,         // 子设备 → 同上（也可换其他）
  COMPONENT: Tools,    // 部件 → 扳手
  PART: CopyDocument,  // 零件 → 文档/标识（可按需换）
}

const iconOf = (row) => {
  console.log(row)
  const t = (row?.nodeType || row?.type || '').toUpperCase()
  return TYPE_ICON[t] || Cpu
}

/** 工具：名称 */
const dispName = (d) => d?.name ?? d?.label ?? "";
// 为空判断：null / undefined / "" / "   "
const isBlank = (v) =>
  v === null || v === undefined || (typeof v === "string" && v.trim() === "");

// 为空则返回 "-"
const fmt = (v, dash = "-") => (isBlank(v) ? dash : v);

// 判断是否为 "NA"（大小写不敏感）
const isNA = (v) => typeof v === "string" && v.trim().toUpperCase() === "NA";

// 带单位显示：空或 "NA" 则返回 "-"
const fmtUnit = (v, unit, dash = "-") =>
  isBlank(v) || isNA(v) ? dash : `${v}${unit}`;

/** 右侧操作 */
function doAdd() {
  if (detail.value) props.onAdd?.(detail.value);
}
function doEdit() {
  if (detail.value) props.onEdit?.(detail.value);
}
function doRemove() {
  if (detail.value) props.onRemove?.(detail.value);
}
function doHistory() {
  if (detail.value) props.onHistory?.(detail.value);
}

function doRefresh() {
  props.onRefresh?.(detail.value);
  if (detail.value?.id && props.loadDetail) {
    props.loadDetail(detail.value.id).then((r) => {
      if (r) detail.value = r;
    });
  }
}

/** 类型与颜色 */
const typeText = (d) => {
  const raw = d?.type ?? d?.typeLabel ?? d?.nodeType ?? "";
  const t = String(raw).toUpperCase();
  switch (t) {
    case "SYSTEM":
      return "系统";
    case "MACHINE":
      return "母设备";
    case "MODULE":
      return "子设备";
    case "COMPONENT":
      return "部件";
    case "PART":
      return "零件";
    default:
      return String(raw) || "—";
  }
};
const shortType = (txt) =>
  String(txt).length === 3 ? String(txt).slice(0, 2) : txt;
function levelColor(level) {
  const palette = [
    "#67C23A",
    "#409EFF",
    "#E6A23C",
    "#F56C6C",
    "#909399",
    "#9B59B6",
    "#1ABC9C",
    "#2D8CF0",
  ];
  return palette[(Math.max(1, Number(level || 1)) - 1) % palette.length];
}
const TAG_COLORS = {
  系统: "#67C23A",
  SYSTEM: "#67C23A",
  母设备: "#409EFF",
  MACHINE: "#409EFF",
  子设备: "#E6A23C",
  MODULE: "#E6A23C",
  部件: "#F56C6C",
  COMPONENT: "#F56C6C",
  零件: "#909399",
  PART: "#909399",
  default: "#1ABC9C",
};
function hex2rgba(hex, a = 1) {
  const h = hex.replace("#", "");
  const r = parseInt(h.slice(0, 2), 16),
    g = parseInt(h.slice(2, 4), 16),
    b = parseInt(h.slice(4, 6), 16);
  return `rgba(${r},${g},${b},${a})`;
}
function getColor(type) {
  const k = String(type || "");
  return TAG_COLORS[k] || TAG_COLORS[k.toUpperCase()] || TAG_COLORS.default;
}
function softTagStyle(type) {
  const c = getColor(type);
  return {
    "--tag-fg": c,
    "--tag-bg": hex2rgba(c, 0.12),
    "--tag-bd": hex2rgba(c, 0.22),
  };
}

/** 过滤 */
function filterNode(value, data) {
  if (!value) return true;
  const v = String(value).toLowerCase();
  const base =
    (data._rawName || "") +
    (data._rawCode || "") +
    (data.label || "") +
    (data.name || "");
  return base.toLowerCase().includes(v);
}
function mapGet(id) {
  if (props.detailMap instanceof Map) return props.detailMap.get(id);
  return props.detailMap?.[id];
}

/** Tree helpers */
function getAllTreeNodes() {
  const tree = treeRef.value;
  if (!tree) return [];
  const out = [];
  function walk(node) {
    if (!node) return;
    out.push(node);
    if (Array.isArray(node.childNodes)) node.childNodes.forEach(walk);
  }
  tree.root?.childNodes?.forEach(walk);
  return out;
}
function expandAllDescendants(node) {
  if (!node) return;
  node.expand && node.expand();
  if (Array.isArray(node.childNodes))
    node.childNodes.forEach(expandAllDescendants);
}
function collapseAllDescendants(node) {
  if (!node) return;
  if (Array.isArray(node.childNodes))
    node.childNodes.forEach(collapseAllDescendants);
  node.collapse && node.collapse();
}
function isRootNode(node) {
  return !node?.parent || node.level === 1; // Element Plus: 根的 level=1
}

/** —— 仅对“当前节点”显示下一层（不影响其它分支） —— */
async function revealNextLevel(node) {
  const tree = treeRef.value;
  if (!node || !tree) return;
  suppressAuto.value = true;

  // 1) 展开祖先（只影响路径所需的父级）
  let p = node.parent;
  while (p) {
    p.expand && p.expand();
    p = p.parent;
  }

  // 2) 展开当前节点本身
  node.expand && node.expand();
  await nextTick();

  // 3) 折叠该节点所有“孙辈及以下”，保证只露出“下一层”
  if (Array.isArray(node.childNodes)) {
    node.childNodes.forEach((child) => {
      // 先折叠孩子的所有后代
      collapseAllDescendants(child);
      // 保持孩子自身为“折叠”（仅一层可见）
      child.collapse && child.collapse();
    });
  }

  // 4) 聚焦
  tree.setCurrentKey?.(node.key);
  suppressAuto.value = false;
}

/** —— 详情加载 —— */
async function selectNodeAndShowByNode(node) {
  if (!node) return;
  const id = node.data?.id;
  if (!id) return;
  treeRef.value?.setCurrentKey(node.key);
  selectedId.value = id;
  detail.value = {};
  try {
    if (props.loadDetail) {
      const row = await props.loadDetail(id);
      console.log(row);
      console.log("selectNodeAndShowByNode");
      if (row) detail.value = row;
    } else {
      const local = mapGet(id);
      if (local) detail.value = local;
    }
  } catch {}
}

/** —— 行交互（仅影响当前节点） —— */
async function handleNodeClick(node) {
  if (!node) return;
  // 无论原来是展开还是收起，统一“只显示下一层”
  await revealNextLevel(node);
  await selectNodeAndShowByNode(node);
}
async function handleNodeDblClick(node) {
  if (!node || node.isLeaf) return;
  // 双击：如果当前已展开，改为只下一层（与单击一致）；如果收起则同样只下一层
  await revealNextLevel(node);
  await selectNodeAndShowByNode(node);
}

/** —— caret 交互（仅影响当前节点） —— */
async function onCaretExpand(data, node) {
  if (suppressAuto.value) return;
  // 根节点 caret 也不全展开，只做“当前节点下一层”
  await revealNextLevel(node);
}
async function onCaretCollapse(data, node) {
  if (suppressAuto.value) return;
  // 只收起当前节点（及其子孙），不动其它分支
  collapseAllDescendants(node);
}

/** —— 仅根节点自定义箭头：全局“展开所有/收起所有” —— */
async function toggleExpandAll() {
  const tree = treeRef.value;
  if (!tree) return;
  suppressAuto.value = true;
  if (allOpen.value) {
    // 收起所有
    getAllTreeNodes().forEach((n) => n.collapse && n.collapse());
    allOpen.value = false;
  } else {
    // 展开所有到叶子
    tree.root?.childNodes?.forEach((r) => expandAllDescendants(r));
    allOpen.value = true;
  }
  suppressAuto.value = false;
}

/** —— 初始化：显示叶子（全展开），并选中第一个叶子 —— */
async function expandAllAndSelectFirstLeaf() {
  const tree = treeRef.value;
  if (!tree) return;
  suppressAuto.value = true;

  // 展开所有
  tree.root?.childNodes?.forEach((r) => expandAllDescendants(r));
  allOpen.value = true;
  await nextTick();

  // 选中第一个“叶子”
  let firstLeaf = null;
  function findLeaf(nodes) {
    for (const n of nodes || []) {
      if (!n.childNodes || n.childNodes.length === 0) return n;
      const got = findLeaf(n.childNodes);
      if (got) return got;
    }
    return null;
  }
  firstLeaf = findLeaf(tree.root?.childNodes || []);
  suppressAuto.value = false;

  if (firstLeaf) {
    await selectNodeAndShowByNode(firstLeaf);
  } else {
    detail.value = null;
  }
}

async function expandRootAndShowOneLevel() {
  const tree = treeRef.value;
  if (!tree) return;
  suppressAuto.value = true;

  // 1) 先全部收起，保证干净的初始状态
  getAllTreeNodes().forEach((n) => n.collapse && n.collapse());

  // 2) 展开所有“根节点”，并仅展示其“下一层”
  const roots = tree.root?.childNodes || [];
  roots.forEach((r) => {
    r.expand && r.expand(); // 展开根
    // 折叠子节点的后代，保证只出现下一层
    (r.childNodes || []).forEach((child) => {
      collapseAllDescendants(child); // 折叠孙辈及以下
      child.collapse && child.collapse(); // 保证 child 自身是“收起”的（只显示为一行）
    });
  });

  // 3) 默认选中第一个根节点并加载详情（右侧显示根节点数据）
  const firstRoot = roots[0];
  if (firstRoot) {
    tree.setCurrentKey?.(firstRoot.key);
    await selectNodeAndShowByNode(firstRoot);
  } else {
    detail.value = null;
  }

  // 标记“非全局展开”
  allOpen.value = false;
  suppressAuto.value = false;
}

const pathText = computed(() => {
  const id = detail.value?.id;
  return (
    (props.getPath
      ? id
        ? props.getPath(id)
        : ""
      : detail.value?.path || "") || ""
  );
});

// 备件列表（始终返回数组）
const spareList = computed(() => {
  const arr = detail.value?.spareInfos;
  return Array.isArray(arr) ? arr : [];
});

function used(sp) {
  const t = Number(sp?.stockTotal ?? 0);
  const a = Number(sp?.stockAvailable ?? 0);
  return Math.max(0, t - a);
}

async function copyPath() {
  const text = pathText.value?.trim();
  if (!text) {
    ElMessage.warning("暂无可复制的路径");
    return;
  }
  try {
    await navigator.clipboard.writeText(text);
    ElMessage.success("已复制");
  } catch (e) {
    // 兼容旧环境的兜底复制
    const ta = document.createElement("textarea");
    ta.value = text;
    ta.style.position = "fixed";
    ta.style.left = "-9999px";
    document.body.appendChild(ta);
    ta.select();
    try {
      document.execCommand("copy");
      ElMessage.success("已复制");
    } catch {
      ElMessage.error("复制失败");
    } finally {
      document.body.removeChild(ta);
    }
  }
}

/** —— nodes 变化 —— */
watch(
  () => props.nodes,
  async () => {
    expandedKeys.value = []; // 由我们手动控制展开
    treeKey.value++;
    await nextTick();
    await expandAllAndSelectFirstLeaf();
  },
  { immediate: true, deep: true }
);
</script>

<style scoped>
.split {
  display: grid;
  grid-template-columns: 360px 1fr;
  gap: 12px;
}
.toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 10px;
}
.toolbar .spacer {
  flex: 1;
}

.tree {
  border: 1px solid #f0f2f5;
  border-radius: 8px;
  padding: 8px 10px;
  background: #fff;
}
.node-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 28px;
}
.name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 260px;
}
.meta {
  display: inline-flex;
  gap: 6px;
  flex-shrink: 0;
}
.ml6 {
  margin-left: 6px;
}

.right {
  background: #fff;
  border: 1px solid #f0f2f5;
  border-radius: 8px;
  padding: 12px;
}
.path {
  word-break: break-all;
}

/* --- 容器 --- */
.tree.leveled {
  border: 1px solid #eef2f6;
  border-radius: 10px;
  background: #fff;
  padding: 6px 8px;
}
:deep(.el-tree-node__content) {
  height: 34px;
  border-radius: 8px;
}
:deep(.el-tree-node__expand-icon) {
  color: #9aa8b3;
}

/* 行内容 */
.tree-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
}
.tree-row .prefix {
  color: #9aa8b3;
  display: inline-flex;
  align-items: center;
}
.tree-row .title {
  color: #3e8cf0;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1 1 auto;
}
.tree-row .badges {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}

/* 胶囊 */
.pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 20px;
  line-height: 20px;
  padding: 0 8px;
  font-size: 12px;
  border-radius: 999px;
  border: 1px solid transparent;
  user-select: none;
}
.pill.lv {
  min-width: 24px;
  background: #e8f3ff;
  color: #3e8cf0;
  border-color: #d7e8ff;
  font-weight: 700;
}
.pill.tag {
  background: #f5f7fa;
  color: #5e6b76;
  border-color: #e8edf2;
}

/* 子数徽章 */
.dot {
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: 999px;
  background: #ecf5ff;
  color: #409eff;
  font-size: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid #d9ecff;
}

/* 悬浮/高亮 */
:deep(.el-tree-node__content:hover) {
  background: #f3f7ff;
}
:deep(
    .el-tree--highlight-current
      .el-tree-node.is-current
      > .el-tree-node__content
  ) {
  background: #eaf2ff;
}

/* 目录左侧竖线装饰 */
:deep(.el-tree-node) {
  position: relative;
}
:deep(.el-tree-node:before) {
  content: "";
  position: absolute;
  left: 10px;
  top: 34px;
  bottom: -6px;
  width: 1px;
  background: linear-gradient(#edf2f7, #edf2f7);
  opacity: 0.6;
}
:deep(.el-tree > .el-tree-node:before) {
  display: none;
}

.root-arrow {
  width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
  user-select: none;
  border: 1px solid var(--el-border-color);
  background: var(--el-fill-color-blank);
  transition: background-color 0.15s ease, color 0.15s ease,
    border-color 0.15s ease;
}
.root-arrow.leaf {
  opacity: 0.45;
  pointer-events: none;
}
.root-arrow.open {
  color: #e6a23c;
  background: #fdf6ec;
  border-color: #f3d19e;
}
.root-arrow:not(.open) {
  color: #409eff;
  background: #ecf5ff;
  border-color: #b3d8ff;
}
.root-arrow.open:hover {
  background: #faecd8;
  border-color: #e8c08d;
}
.root-arrow:not(.open):hover {
  background: #e6f0ff;
  border-color: #8cc5ff;
}

/* 树宽滚动设置 */
.left {
  width: 360px;
  min-width: 360px;
}
.tree-viewport {
  height: 66vh;
  overflow: auto;
}
.wide-tree {
  min-width: max-content;
}
.asset-tree :deep(.el-tree-node__content) {
  width: auto !important;
}
.asset-tree :deep(.node-line) {
  width: max-content;
  white-space: nowrap;
}
.asset-tree :deep(.node-left .name-colored) {
  overflow: visible;
  text-overflow: clip;
}

.asset-tree :deep(.node-line) {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 8px;
  width: 100%;
  white-space: nowrap;
  cursor: pointer;
}
.asset-tree :deep(.node-left) {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.asset-tree :deep(.node-left .name-colored) {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.asset-tree :deep(.node-right) {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* 同层级配色（配合 --lvl-color） */
.asset-tree :deep(.name-colored) {
  color: var(--lvl-color);
  font-weight: 600;
}

/* 柔和芯片风格标签 */
.tag-soft {
  --tag-fg: #606266;
  --tag-bg: #f5f7fa;
  --tag-bd: #e4e7ed;
  color: var(--tag-fg) !important;
  background: var(--tag-bg) !important;
  border-color: var(--tag-bd) !important;
  border-radius: var(--el-border-radius-base) !important;
}

/* 左侧树字号微调 */
.asset-tree :deep(.el-tree-node__content) {
  font-size: 13px;
  font-weight: 400;
}
.asset-tree :deep(.node-left .name-colored) {
  font-weight: 300 !important;
  opacity: 0.9;
}
.asset-tree :deep(.name-colored) {
  font-weight: 300 !important;
}

/* descriptions：固定 label 宽度 */
.kv-desc:deep(td.el-descriptions__label) {
  width: 140px;
  white-space: nowrap;
  vertical-align: top;
}
.kv-desc:deep(td.el-descriptions__content) {
  word-break: break-all;
  white-space: normal;
  vertical-align: top;
}
.kv-desc:deep(table.el-descriptions__table) {
  table-layout: fixed;
}

/* 右侧容器与按钮条 */
.right {
  position: relative;
  background: #fff;
  border: 1px solid #f0f2f5;
  border-radius: 8px;
  padding: 44px 12px 12px;
  overflow: auto;
}
.actions {
  position: absolute;
  left: 12px;
  top: 8px;
  display: inline-flex;
  gap: 8px;
  z-index: 2;
  background: rgba(255, 255, 255, 0.9);
  padding: 4px 6px;
  backdrop-filter: saturate(180%) blur(8px);
}
@media (max-width: 1024px) {
  .actions .btn-text {
    display: none;
  }
}

:root,
:host {
  --left-pane-w: 260px;
} /* 想多窄就改这里 */

.split {
  display: grid;
  grid-template-columns: var(--left-pane-w) 1fr;
  gap: 12px;
}
.left {
  width: var(--left-pane-w);
  min-width: var(--left-pane-w);
}

.path-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.path-row .path {
  flex: 1 1 auto;
  word-break: break-all;
}

/* 五列：全部等宽 */
.spares-grid {
  display: grid;
  grid-template-columns: repeat(var(--cols, 5), minmax(0, 1fr));
  gap: 8px 12px;
  width: 100%;
}

/* 表头和单元都用 flex，默认水平居中 */
.spares-grid .sp-head,
.spares-grid .sp-cell {
  display: flex;
  align-items: center;
  justify-content: center; /* 默认居中 */
}

/* 名称/编码两列改为左对齐 */
.spares-grid .sp-head.name,
.spares-grid .sp-head.code,
.spares-grid .sp-name,
.spares-grid .sp-code {
  justify-content: flex-start;
}

.code-pill {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono",
    monospace;
  background: #f5f7fa !important;
  border-color: #e4e7ed !important;
  border-radius: 6px !important;
  height: 22px;
  display: inline-flex;
  align-items: center;
}

/* 数字徽章：等宽数字，三种语义色 */
.num-badge {
  display: inline-block;
  padding: 0 6px;
  line-height: 20px;
  height: 20px;
  border-radius: 6px;
  border: 1px solid #d9ecff;
  background: #ecf5ff;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.num-badge.plain {
  background: #eef5ff;
  border-color: #d6e6ff;
} /* 总数（中性） */
.num-badge.warn {
  background: #fff7e6;
  border-color: #ffe3bf;
} /* 使用（暖色） */

/* 小屏降级：3 列（名称/编码/数字块），数字块自动换行 */
@media (max-width: 640px) {
  .spares-grid {
    grid-template-columns: 1.2fr 1fr 1fr;
  }
  .spares-grid .sp-head:nth-child(3),
  .spares-grid .sp-head:nth-child(4),
  .spares-grid .sp-head:nth-child(5) {
    display: none;
  }
}

.spares-grid.cols-4 {
  grid-template-columns: var(--name-col) var(--code-col) var(--num-col) var(
      --num-col
    );
}
.spares-grid.cols-5 {
  grid-template-columns: var(--name-col) var(--code-col) var(--num-col) var(
      --num-col
    ) var(--num-col);
}
.spares-grid.cols-6 {
  grid-template-columns:
    var(--name-col) var(--code-col)
    var(--num-col) var(--num-col) var(--num-col) var(--num-col);
}

@media (max-width: 640px) {
  .spares-grid {
    grid-template-columns: 1.2fr 1fr;
  }
  .spares-grid .sp-head:nth-child(n + 3) {
    display: none;
  }
}

/* 占位换行：隐藏边框/间距，只起到“补格子换行”的作用 */
.kv-desc:deep(.dl-break td) {
  padding: 0 !important;
  border: none !important;
}
</style>
